/**
 * Copyright (C) 2007 The AsyncMail Group <asyncmail@googlegroups.com>
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *         http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.googlecode.asyncmail.smtpserver.mina;

import org.apache.mina.common.IoSession;

import com.googlecode.asyncmail.smtp.SMTPResponse;
import com.googlecode.asyncmail.smtpserver.SMTPHandlerConfigurationData;
import com.googlecode.asyncmail.smtpserver.SMTPSession;
import com.googlecode.asyncmail.smtpserver.handler.LineHandler;

import java.net.InetSocketAddress;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

public class SMTPSessionImpl implements SMTPSession {

    private static Random random = new Random();

    private boolean relayingAllowed;

    private String smtpID;

    private Map<String, Object> connectionState;

    private SMTPHandlerConfigurationData theConfigData;

    private InetSocketAddress socketAddress;

    private String user;

    private IoSession session;

    private int lineHandlerCount = 0;

    public SMTPSessionImpl(SMTPHandlerConfigurationData theConfigData,
            IoSession session) {
        this.theConfigData = theConfigData;
        this.session = session;
        connectionState = new HashMap<String, Object>();
        smtpID = random.nextInt(1024) + "";

        this.socketAddress = (InetSocketAddress) session.getRemoteAddress();
        relayingAllowed = theConfigData.isRelayingAllowed(socketAddress
                .getAddress().toString());
        session.setAttribute(MinaFilterLineHandlerAdapter.SMTP_SESSION, this);
    }

    /**
     * @see com.googlecode.asyncmail.smtpserver.SMTPSession#getConfigurationData()
     */
    public SMTPHandlerConfigurationData getConfigurationData() {
        return theConfigData;
    }

    /**
     * @see com.googlecode.asyncmail.smtpserver.SMTPSession#getConnectionState()
     */
    public Map<String, Object> getConnectionState() {
        return connectionState;
    }

    /**
     * @see com.googlecode.asyncmail.smtpserver.SMTPSession#getRemoteHost()
     */
    public String getRemoteHost() {
        return socketAddress.getHostName();
    }

    /**
     * @see com.googlecode.asyncmail.smtpserver.SMTPSession#getRemoteIPAddress()
     */
    public String getRemoteIPAddress() {
        return socketAddress.getAddress().getHostAddress();
    }

    /**
     * @see com.googlecode.asyncmail.smtpserver.SMTPSession#getSessionID()
     */
    public String getSessionID() {
        return smtpID;
    }

    /**
     * @see com.googlecode.asyncmail.smtpserver.SMTPSession#getState()
     */
    @SuppressWarnings("unchecked")
    public Map<String, Object> getState() {
        Map<String, Object> res = (Map<String, Object>) getConnectionState()
                .get(SMTPSession.SESSION_STATE_MAP);
        if (res == null) {
            res = new HashMap<String, Object>();
            getConnectionState().put(SMTPSession.SESSION_STATE_MAP, res);
        }
        return res;
    }

    /**
     * @see com.googlecode.asyncmail.smtpserver.SMTPSession#getUser()
     */
    public String getUser() {
        return user;
    }

    /**
     * @see com.googlecode.asyncmail.smtpserver.SMTPSession#isRelayingAllowed()
     */
    public boolean isRelayingAllowed() {
        return relayingAllowed;
    }

    /**
     * @see com.googlecode.asyncmail.smtpserver.SMTPSession#resetState()
     */
    public void resetState() {
        // remember the ehlo mode between resets
        Object currentHeloMode = getState().get(CURRENT_HELO_MODE);

        getState().clear();

        // start again with the old helo mode
        if (currentHeloMode != null) {
            getState().put(CURRENT_HELO_MODE, currentHeloMode);
        }
    }

    /**
     * @see com.googlecode.asyncmail.smtpserver.SMTPSession#setUser(java.lang.String)
     */
    public void setUser(String user) {
        this.user = user;
    }

    /**
     * @see com.googlecode.asyncmail.smtpserver.SMTPSession#getIoSession()
     */
    public IoSession getIoSession() {
        return session;
    }

    /**
     * @see com.googlecode.asyncmail.smtpserver.SMTPSession#popLineHandler()
     */
    public void popLineHandler() {
        getIoSession().getFilterChain()
                .remove("lineHandler" + lineHandlerCount);
        lineHandlerCount--;
    }

    /**
     * @see com.googlecode.asyncmail.smtpserver.SMTPSession#pushLineHandler(com.googlecode.asyncmail.smtpserver.handler.LineHandler)
     */
    public void pushLineHandler(LineHandler overrideCommandHandler) {
        lineHandlerCount++;
        getIoSession().getFilterChain().addAfter("protocolCodecFactory",
                "lineHandler" + lineHandlerCount,
                new MinaFilterLineHandlerAdapter(overrideCommandHandler));
    }

    /**
     * @see com.googlecode.asyncmail.smtpserver.SMTPSession#writeSMTPResponse(com.googlecode.asyncmail.smtp.SMTPResponse)
     */
    public void writeSMTPResponse(SMTPResponse response) {
        getIoSession().write(response);
    }

}
